package com.commons.dbutils.pool;

import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.qunar.sandglass.mina.handler.ClientHandler;

public class TCPConnectionPool {
	private final static Logger log = LoggerFactory
			.getLogger(TCPConnectionPool.class);
	// private int checkedOut;
//	private Vector<SocketChannel> freeConnections = new Vector<SocketChannel>();
	Map<SocketChannel,Boolean> connections = new ConcurrentHashMap<SocketChannel,Boolean>();
	
	private int maxConn;
	private String ip;
	private int port;
	private String name;
	 private static Selector selector  = null;
	 private static InetSocketAddress SERVER_ADDRESS = null; 
	
	//默认初始化连接数
	private static final int CONNECTION_POOL_SIZE = 10;
	/**
	 * 创建新的连接池
	 * 
	 * @param name
	 *            连接池名字
	 * @param URL
	 *            数据库的JDBC URL
	 * @param maxConn
	 *            此连接池允许建立的最大连接数
	 */
	public TCPConnectionPool( String name,String ip,int port ,int maxConn) {
		this.name=name;
		this.ip = ip;
		this.maxConn = maxConn;
		this.port= port;
	}
	
	public synchronized void initConectionPool()throws Exception{
		 for (int i = 0; i < CONNECTION_POOL_SIZE; i++) {
			   SocketChannel client = allocateSocketChannel();
			   self.socketPool.put(new Integer(i), client);
			   self.socketStatusArray[i] = false;
		 }
	}
	
	
	/**
	 * 将不再使用的连接返回给连接池
	 * 
	 * @param con
	 *            客户程序释放的连接
	 */
	public synchronized void freeConnection(Connection con) {
		// 将指定连接加入到向量末尾
		try {
			if (con.isClosed()) {
				System.out.println("before freeConnection con is closed");
			}
			freeConnections.addElement(con);
			Connection contest = (Connection) freeConnections.lastElement();
			if (contest.isClosed()) {
				System.out.println("after freeConnection contest is closed");
			}
			notifyAll();
		} catch (Exception e) {
			log.error("TCPConnectionPool.freeConnection(...) Exception", e);
		}
	}

	/**
	 * 从连接池获得一个可用连接.如没有空闲的连接且当前连接数小于最大连接 数限制,则创建新连接.如原来登记为可用的连接不再有效,则从向量删除之,
	 * 然后递归调用自己以尝试新的可用连接.
	 */
	public synchronized Connection getConnection() {
		Connection con = null;
		if (freeConnections.size() > 0) {
			// 获取向量中第一个可用连接
			con = (Connection) freeConnections.firstElement();
			freeConnections.removeElementAt(0);
			try {
				if (con.isClosed()) {
					log("从连接池" + name + "删除一个无效连接");
					System.out.println("从连接池" + name + "删除一个无效连接");
					// 递归调用自己,尝试再次获取可用连接
					con = getConnection();
				}
			} catch (SQLException e) {
				log("从连接池" + name + "删除一个无效连接时错误");
				System.out.println("从连接池" + name + "删除一个无效连接出错");
				// 递归调用自己,尝试再次获取可用连接
				con = getConnection();
			}
			if (freeConnections.size() > maxConn) {
				System.out.println(" 删除一个溢出连接 ");
				releaseOne();
			}
		}

		else if ((maxConn == 0) || (freeConnections.size() < maxConn)) {
			con = newConnection();
		}

		return con;
	}

	public synchronized Connection returnConnection() {
		Connection con = null;
		// 如果闲置小于最大连接,返回一个新连接
		if (freeConnections.size() < maxConn) {
			con = newConnection();
		}
		// 如果闲置大于最大连接，返回一个可用的旧连接
		else if (freeConnections.size() >= maxConn) {

			con = (Connection) freeConnections.firstElement();
			System.out.println(" [a 连接池可用连接数 ] : " + "[ "
					+ freeConnections.size() + " ]");
			freeConnections.removeElementAt(0);
			System.out.println(" [b 连接池可用连接数 ] : " + "[ "
					+ freeConnections.size() + " ]");
			try {
				if (con.isClosed()) {
					log("从连接池" + name + "删除一个无效连接");
					System.out.println("从连接池" + name + "删除一个无效连接");
					returnConnection();
				}
			} catch (SQLException e) {
				log("从连接池" + name + "删除一个无效连接时错误");
				System.out.println("从连接池" + name + "删除一个无效连接出错");
				returnConnection();
			}
		}
		return con;
	}

	/**
	 * 从连接池获取可用连接.可以指定客户程序能够等待的最长时间 参见前一个getConnection()方法.
	 * 
	 * @param timeout
	 *            以毫秒计的等待时间限制
	 */
	public synchronized Connection getConnection(long timeout) {
		long startTime = new Date().getTime();
		Connection con;
		while ((con = getConnection()) == null) {
			try {
				wait(timeout);
			} catch (InterruptedException e) {
			}
			if ((new Date().getTime() - startTime) >= timeout) {
				// wait()返回的原因是超时
				return null;
			}
		}
		return con;
	}

	 /**
	  * 将用完的socket放回池中，调整为空闲状态。此时连接并没有断开。
	  * 
	  * @param socket
	  *            使用完的socket
	  * @throws Exception
	  */
	 public void releaseConnection(SocketChannel socket) throws Exception {
		 
		if(connections.containsKeysocket)){
			freeConnections.
			
		}else{
			log.warn("SocketChannel isn't have in  "+name+" TCPConnectionPool.");
		}
		 
	  for (int i = 0; i < CONNECTION_POOL_SIZE; i++) {
		  
	   if (self.socketPool.get(new Integer(i)) == socket) {
	    self.socketStatusArray[i] = false;
	    break;
	   }
	  }
	 }

	/**
	 * 创建新的连接
	 */
	private Connection newConnection() {
		Connection con = null;
		try {
			if (user == null) {
				con = DriverManager.getConnection(URL);
			} else {
				con = DriverManager.getConnection(URL, user, password);
			}
			log("连接池" + name + "创建一个新的连接");

		} catch (SQLException e) {
			log(e, "无法创建下列URL的连接: " + URL);
			return null;
		}
		return con;
	}
	
	
	public  SocketChannel allocateSocketChannel(){
		  
		SERVER_ADDRESS = new InetSocketAddress(this.ip, this.port);
		SocketChannel socketChannel = null;
		SocketChannel client = null;
		try {
			socketChannel = SocketChannel.open();
			socketChannel.configureBlocking(false);
			selector = Selector.open();
			socketChannel.register(selector, SelectionKey.OP_CONNECT);
			socketChannel.connect(SERVER_ADDRESS);
			Set<SelectionKey> selectionKeys;
			Iterator<SelectionKey> iterator;
			SelectionKey selectionKey;
			selector.select();
			selectionKeys = selector.selectedKeys();
			iterator = selectionKeys.iterator();
			while (iterator.hasNext()) {
				selectionKey = iterator.next();
				if (selectionKey.isConnectable()) {
					client = (SocketChannel) selectionKey.channel();
					if (client.isConnectionPending()) {
						client.finishConnect();
						client.register(selector, SelectionKey.OP_WRITE);
						break;
					}
				}
			}
		} catch (Exception e) {
			log.error("TCPConnectionPool.allocateSocketChannel(...) exception.",e);
		}
		return client;
	}

	public Selector getSelector() {
		return selector;
	}
}
